001    /**
002     * Java Gui Builder - A library to build GUIs using an XML file.
003     * Copyright 2002, 2003 (C) François Beausoleil
004     *
005     * This library is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU Lesser General Public
007     * License as published by the Free Software Foundation; either
008     * version 2.1 of the License, or (at your option) any later version.
009     *
010     * This library is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013     * Lesser General Public License for more details.
014     *
015     * You should have received a copy of the GNU Lesser General Public
016     * License along with this library; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018     */
019    
020    package jgb.builder.utils;
021    
022    import java.lang.reflect.Method;
023    import java.util.Arrays;
024    
025    /**
026     * An object that accumulates parameters until such time the caller is ready
027     * to call the specified method.
028     * When the caller is ready to call the method, it calls {@link #call() call()}
029     * to get a reference to the return value of the method.  If the named method
030     * returns <code>void</code>, {@link #call() call()} returns
031     * <code>null</code> (just like
032     * {@link java.lang.reflect.Method#invoke(Object, Object[]) Method.invoke(Object, Object[])}).
033     * @since 0.2a
034     * @author Francois Beausoleil, <a href="mailto:fbos@users.sourceforge.net">fbos@users.sourceforge.net</a>
035     */
036    public class MethodCall extends ParametersAccumulator {
037        private Class calledClass;
038        private String methodName;
039        private Object callingObject;
040    
041        protected MethodCall(String className) throws ClassNotFoundException {
042            calledClass = Class.forName(className);
043        }
044    
045        public MethodCall(String className, String methodName, Object callingObject) throws ClassNotFoundException, NoSuchMethodException {
046            this(className);
047            this.methodName = methodName;
048            this.callingObject = callingObject;
049    
050            checkMethodExists(methodName);
051        }
052    
053        public Class getReturnValueType() {
054            try {
055                Method method = findMethod();
056                return method.getReturnType();
057            } catch (NoSuchMethodException e) {
058                RuntimeException e1 =
059                        new RuntimeException("Could not find method that existed earlier:  "
060                        + e.getMessage());
061                e1.printStackTrace();
062                throw e1;
063            }
064        }
065    
066        public String getMethodName() {
067            return methodName;
068        }
069    
070        public Class getCalledClass() {
071            return calledClass;
072        }
073    
074        public Object call() throws NoSuchMethodException, MethodCallException {
075            try {
076                return findMethod().invoke(callingObject, createValuesArray());
077            } catch (NoSuchMethodException e) {
078                throw new NoSuchMethodException("Could not execute method " + methodName
079                        + " on object's of class " + calledClass + " with parameters "
080                        + Arrays.asList(createParametersArray()));
081            } catch (Exception e) {
082                throw new MethodCallException(e);
083            }
084        }
085    
086        private Method findMethod() throws NoSuchMethodException {
087            Class[] callingTypes = createParametersArray();
088            Method[] allMethods = calledClass.getMethods();
089            for (int i = 0; i < allMethods.length; i++) {
090                Method method = allMethods[i];
091                if (method.getName().equals(methodName)) {
092                    Class[] paramTypes = method.getParameterTypes();
093                    if (paramTypes.length == callingTypes.length) {
094                        boolean compatible = true;
095                        for (int j = 0; j < paramTypes.length; j++) {
096                            if (isCompatible(paramTypes[j], callingTypes[j])) {
097                                compatible = false;
098                                break;
099                            }
100                        }
101    
102                        if (compatible) {
103                            return method;
104                        }
105                    }
106                }
107            }
108    
109            throw new NoSuchMethodException("Class " + getCalledClass().getName()
110                    + " does not have a method with arguments of type " + getParameterTypes());
111        }
112    
113        private boolean isCompatible(Class type, Class callingType) {
114            return false == type.isAssignableFrom(callingType);
115        }
116    
117        private void checkMethodExists(String methodName) throws NoSuchMethodException {
118            boolean methodFound = false;
119            Method[] methods = calledClass.getMethods();
120            for (int i = 0; i < methods.length; i++) {
121                Method method = methods[i];
122                if (method.getName().equals(methodName)) {
123                    methodFound = true;
124                    break;
125                }
126            }
127    
128            if (methodFound == false) {
129                throw new NoSuchMethodException("no method with the specified name - "
130                        + methodName + " on objects of class " + calledClass.getName());
131            }
132        }
133    }